package com.company.exp2.event.impl;

import com.company.exp2.context.Context;
import com.company.exp2.event.Event;
import com.company.exp2.factory.EventFactory;
import com.company.exp2.frame.Frame;
import com.company.exp2.station.Station;
import com.company.exp2.typeEnum.EventType;
import com.company.exp2.util.C;
import com.company.exp2.util.DistributionGenerator;

/**
 * @author dyy
 */
public class CreateFrameEvent extends Event {

    private static long creationCount = 0L;
    private final DistributionGenerator generator;

    {
        generator = new DistributionGenerator(C.EXPECTED_POISSON, C.EXPECTED_EXP);
    }

    /**
     * @param timestamp         事件发生的时间戳
     * @param associatedStation 与事件相关的站点
     */
    public CreateFrameEvent(long timestamp, Station associatedStation) {
        super(timestamp, associatedStation);
    }

    @Override
    public void occur() {
        long duration = generateDuration();
        Frame frame = new Frame(
                getAssociatedStation(),
                duration);
        associatedStation.insertFrame(frame, getTimestamp());
        if (creationCount <= C.MAX_FRAME_CREATION_COUNT) {
            long nextFrameCreatingTime = generateNextFrameCreatingTime();
            Context.currentContext.getTimeLine().announceAnEvent(
                    EventFactory.createInstance(
                            EventType.CREATE_FRAME,
                            nextFrameCreatingTime,
                            associatedStation
                    )
            );
            creationCount ++;
        }
    }

    @Override
    public EventType getEventType() {
        return EventType.CREATE_FRAME;
    }

    private long generateNextFrameCreatingTime() {
        int poisson = generator.getPoisson();
        return getTimestamp() + poisson * C.CREATE_FRAME_INTERVAL_UNIT;
    }

    private long generateDuration() {
        if (C.TRANSMISSION_DURATION_CHANGEABLE) {
            int exp = generator.getExp();
            return Math.max(C.TRANSMISSION_DURATION_LOWER_LIMIT, Math.min(exp * C.DURATION_TIME_UNIT, C.TRANSMISSION_DURATION_UPPER_LIMIT));
        }
        return C.FIXED_TRANSMISSION_DURATION;
    }

}
